#include <stdio.h>
#include "randomizeInPlace.h"
#include "delta.h"
//#include "sboxes.h"
//#include <pari/pari.h>

int
main (int argc, char **argv)
{

   int indices[64][2];
   for (int i = 0; i < 64; i++)
     {
	indices[i][0] = (i & 1) | ((i & 32) >> 4);
	indices[i][1] =
	   ((i & 2) >> 1) | ((i & 4) >> 1) | ((i & 8) >> 1) | ((i & 16) >> 1);
     }

   //srand(time(NULL));
   const int nbSboxes = 0x100000;
   const int per[16] =
      { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 };

   /*int **sbtest = (int **) malloc (4 * sizeof (int *));
   for (int i = 0; i < 4; i++)
      sbtest[i] = (int *) malloc (16 * sizeof (int));
   for (int i = 0; i < 4; i++)
      for (int j = 0; j < 16; j++)
	 sbtest[i][j] = S[4][i][j];*/

   int fx, fxm, xm, tmp, tmpp, tmppp, tmpppp, bk = 0;
   int deltasLambdas[65][33] = { {0} };
   int ***sBoxes = (int ***) malloc (nbSboxes * sizeof (int **));
   if (sBoxes == NULL)
      abort ();

   for (int k = 0; k < nbSboxes; k++)
     {
	sBoxes[k] = (int **) malloc (4 * sizeof (int *));
	if (sBoxes[k] == NULL)
	   return EXIT_FAILURE;

	for (int i = 0; i < 4; i++)
	  {
	     sBoxes[k][i] = (int *) malloc (16 * sizeof (int));
	     if (sBoxes[k][i] == NULL)
		abort ();

	     for (int j = 0; j < 16; j++)
	       {
		  sBoxes[k][i][j] = per[j];
	       }
	     randomizeInPlace (sBoxes[k][i]);
	  }

	tmp = 63;//fab (sBoxes[k], 13, sBoxes[k][indices[13][0]][indices[13][1]]);
	tmpppp = 1;
	for (int x = 1; x < 64; x++)
	  {
	     fx = sBoxes[k][indices[x][0]][indices[x][1]];
	     for (int j = 1; j < 33; j <<= 1)
	       {
		  xm = x ^ j;
		  //printf("%i  %i\n", x, xm);
		  fxm = sBoxes[k][indices[xm][0]][indices[xm][1]];
		  //printf("fx^fxm: %i\n", fx^fxm);
		  tmppp = nbBits (fx ^ fxm, 4);
		  if (tmppp < 1)
		     tmpppp = 1;
	       }
	  }
	if ((tmp == 64) || (tmpppp == 0))
	  {
	     for (int i = 0; i < 4; i++)
		free (sBoxes[k][i]);
	     free (sBoxes[k]);	//printf("skdjg\n");
	  }

	else
	  {  
	     tmp = 0; tmpp = 0;
	     tmp = delta (sBoxes[k]);
	     //tmp = delta(sbtest);
	     tmpp = lambda (sBoxes[k]);
	     //tmpp = lambda(sbtest);
	     if (tmp == 12 && tmpp == 12)
	       {
		  FILE *goodSboxes = NULL;
		  goodSboxes = fopen ("/tmp/goodSboxes.txt", "a");
		  if (goodSboxes != NULL)
		    {

		       for (int l = 0; l < 4; l++)
			  for (int i = 0; i < 16; i++)
			    {
			       if (i != 15)
				  //fprintf (stderr, "%p  ", goodSboxes);
				  fprintf (goodSboxes, "%i  ",
					   sBoxes[k][l][i]);
			       else
				  fprintf (goodSboxes, "%i\n",
					   sBoxes[k][l][i]);
			    }
			  fprintf(goodSboxes, "\n\n");  
		       fclose (goodSboxes);
		    }
	       }

	     if (tmp == 24 && tmpp == 20 )
	       {
		  FILE *badSboxes = NULL;
		  badSboxes = fopen ("/tmp/badSboxes.txt", "a");
		  if (badSboxes != NULL)
		    {

		       for (int l = 0; l < 4; l++)
			  for (int i = 0; i < 16; i++)
			    {
			       if (i != 15)
				  //fprintf (stderr, "%p  ", goodSboxes);
				  fprintf (badSboxes, "%i  ",
					   sBoxes[k][l][i]);
			       else
				  fprintf (badSboxes, "%i\n",
					   sBoxes[k][l][i]);
			    }
			  fprintf(badSboxes, "\n\n");  
		       fclose (badSboxes);
		    }
	       }

	     deltasLambdas[tmp][tmpp]++;
	     bk = k;
	  }

     }
   /*for (int k = 0; k < 4; k++)
      for (int i = 0; i < 16; i++)
	{
	   if (i != 15)
	      printf ("%i  ", sBoxes[bk][k][i]);
	   else
	      printf ("%i\n", sBoxes[bk][k][i]);
	}
   printf ("delta: %i\n", delta (sBoxes[bk]));*/

   for(int j = 8; j <= 28; j += 2) {
      if (j != 28) 
	    printf("%i\t", j);
	 else
	    printf("%i\n\n", j);
	 }

   for (int i = 10; i <= 64; i += 2)
     {
	for (int j = 8; j <= 28; j += 2)
	  {
	     if (j == 28)
		printf ("%i  delta: %i\n", deltasLambdas[i][j], i);
	     else
		printf ("%i\t", deltasLambdas[i][j]);
	  }
     }
   return 0;
}
